package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.openea.perpartner.common.core.exception.ServiceException;
import cn.openea.perpartner.meily.util.UserContext;
import cn.openea.perpartner.meily.web.entity.Role;
import cn.openea.perpartner.meily.web.entity.RoleMenu;
import cn.openea.perpartner.meily.web.entity.User;
import cn.openea.perpartner.meily.web.entity.UserRole;
import cn.openea.perpartner.meily.web.entity.dto.BtnRoleDto;
import cn.openea.perpartner.meily.web.mapper.RoleMapper;
import cn.openea.perpartner.meily.web.service.IRoleMenuService;
import cn.openea.perpartner.meily.web.service.IRoleService;
import cn.openea.perpartner.meily.web.service.IUserRoleService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Weird077
 * @description TODO
 * @date 2022-12-23 9:11
 */
@Slf4j
@Service
public class RoleServiceImpl extends MPJBaseServiceImpl<RoleMapper, Role> implements IRoleService {
    @Autowired
    private IRoleMenuService roleMenuService;
    @Autowired
    private IUserRoleService userRoleService;

    @Override
    public List<Role> selectRoleList(Role role) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(role.getRoleKey())) {
            wrapper.like(Role::getRoleKey, role.getRoleKey());
        }
        if (StrUtil.isNotBlank(role.getRoleName())) {
            wrapper.like(Role::getRoleName, role.getRoleName());
        }
        wrapper.orderByDesc(Role::getUpdateTime);
        return list(wrapper);
    }

    @Override
    public List<Role> getByRoleKey(String roleKey) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Role::getRoleKey, roleKey);
        return list(wrapper);
    }

    @Override
    public List<Role> getByRoleKeyAndUserId(String roleKey, String userId) {
        MPJLambdaWrapper<Role> wrapper = new MPJLambdaWrapper<Role>()
                .selectAll(Role.class)
                .leftJoin(UserRole.class, UserRole::getRoleId, Role::getRoleId)
                .eq(Role::getRoleKey, roleKey)
                .eq(UserRole::getUserId, userId);
        List<Role> roles = list(wrapper);

        return roles;

    }

    @Override
    public boolean checkAdmin(String userId) {
        MPJLambdaWrapper<Role> wrapper = new MPJLambdaWrapper<Role>()
                .select("1")
                .leftJoin(UserRole.class, UserRole::getRoleId, Role::getRoleId)
                .eq(UserRole::getUserId, userId)
                .eq(Role::getRoleKey, "admin");
        return count(wrapper) > 0;
    }

    @Override
    public List<Role> selectRolesByUserId(String userId) {
        MPJLambdaWrapper<Role> wrapper = new MPJLambdaWrapper<Role>()
                .selectAll(Role.class)
                .leftJoin(UserRole.class, UserRole::getRoleId, Role::getRoleId)
                .leftJoin(User.class, User::getUserId, UserRole::getUserId)
                .eq(Role::getDelFlag, "0")
                .eq(UserRole::getUserId, userId);
        List<Role> userRoles = list(wrapper);
        List<Role> roles = list();
        for (Role role : roles) {
            for (Role userRole : userRoles) {
                if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
                    role.setFlag(true);
                    break;
                }
            }
        }
        return roles;

    }

    @Override
    public boolean checkRoleNameUnique(Role role) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Role::getRoleName, role.getRoleName());
        wrapper.eq(Role::getDelFlag, "0");
        wrapper.last("limit 1");
        return count(wrapper) == 0;
    }

    @Override
    public boolean checkRoleKeyUnique(Role role) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Role::getRoleKey, role.getRoleKey());
        wrapper.eq(Role::getDelFlag, "0");
        wrapper.last("limit 1");
        return count(wrapper) == 0;
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean insertRole(Role role) {
        saveOrUpdate(role);
        return insertRoleMenu(role);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean updateRole(Role role) {
        // 修改角色信息
        updateById(role);
        // 删除角色与菜单关联
        roleMenuService.deleteRoleMenuByRoleId(role.getRoleId());
        return insertRoleMenu(role);
    }

    @Override
    public boolean deleteAuthUser(UserRole userRole) {

        return userRoleService.deleteUserRoleInfo(userRole);
    }

    @Override
    public boolean insertAuthUsers(Long roleId, String userIds) {
        String[] users = Convert.toStrArray(userIds);
        // 新增用户与角色管理
        List<UserRole> list = new ArrayList<>();
        for (String userId : users) {
            UserRole ur = new UserRole();
            ur.setUserId(userId);
            ur.setRoleId(roleId);
            list.add(ur);
        }
        return userRoleService.saveBatch(list);
    }

    @Override
    public boolean deleteAuthUsers(Long roleId, String userIds) {
        return userRoleService.deleteUserRoleInfos(roleId, Convert.toList(String.class, userIds));
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean deleteRoleByIds(List<Long> idList) {
        for (Long roleId : idList) {
            Role role = getById(roleId);
            if (userRoleService.count(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getRoleId, roleId)) > 0) {
                throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }
        // 删除角色与菜单关联
        roleMenuService.remove(Wrappers.<RoleMenu>lambdaQuery().in(RoleMenu::getRoleId, idList));
        return removeByIds(idList);
    }

    @Override
    public BtnRoleDto checkUserRole(BtnRoleDto dto) {
        String userId = dto.getUserId();
        if (StrUtil.isBlank(userId)) {
            userId = UserContext.getUserId();
        }
        JSONObject btnRoles = dto.getBtnRoles();
        BtnRoleDto btnRoleDto = new BtnRoleDto();
        String finalUserId = userId;
        MPJLambdaWrapper<Role> wrapper = new MPJLambdaWrapper<Role>()
                .select("*")
                .leftJoin(UserRole.class, UserRole::getRoleId, Role::getRoleId)
                .eq(UserRole::getUserId, finalUserId);
        List<Role> roles = baseMapper.selectList(wrapper);
        List<String> roleKeyList = roles
                .stream().map(Role::getRoleKey).collect(Collectors.toList());
        btnRoles.forEach((k, v) -> {
            if (roleKeyList.contains("admin")) {
                // 超级管理员给与全部权限
                btnRoles.put(k, true);
                return;
            }
            // 假设全部为 false
            btnRoles.put(k, false);
            String roleKeyStr = (String) v;
            for (String roleKey : roleKeyStr.split(",")) {
                if (btnRoles.getBoolean(k) != null && btnRoles.getBoolean(k)) {
                    break;
                }
                btnRoles.put(k, roleKeyList.contains(roleKey));
            }
        });
        btnRoleDto.setUserId(userId);
        btnRoleDto.setBtnRoles(btnRoles);
        return btnRoleDto;
    }

    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    public boolean insertRoleMenu(Role role) {
        boolean isSuccess = true;
        // 新增用户与角色管理
        List<RoleMenu> list = new ArrayList<>();
        for (Long menuId : role.getMenuIds()) {
            RoleMenu rm = new RoleMenu();
            rm.setRoleId(role.getRoleId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (!list.isEmpty()) {
            isSuccess = roleMenuService.saveBatch(list);
        }
        return isSuccess;
    }
}
